package peer;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.MulticastSocket;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.util.HashMap;
import java.util.Vector;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;

import job.Job;
import job.JobEnvelope;

import protocols.JobProtocol.JobProtocol;
import protocols.joinProtocol.JoinProtocol;
import jobs.Foo.Foo;
import jobs.Foo.Main;
import jobs.Foo.No;

public class Peer implements Runnable {

	public static String tracker;

	public static String id;
		public String getId() { return this.id; }
	protected boolean isLeader = false;
		public boolean isLeader() { return this.isLeader; }

	//MulticastConnection multi;
	Connection parent = null;	// leader of parent group
	Connection childLeader = null; // leader of child group
	Vector<Connection> elders = new Vector<Connection>(); // redundant connection to all nodes in parent group
	Vector<Connection> children = new Vector<Connection>(); //
	LinkedBlockingQueue<JobEnvelope> jobQueue = new LinkedBlockingQueue<JobEnvelope>();
	JavaspaceConnection javaspaceConn = null;

	public Peer(String id) throws IOException {
		this.id = id;		
	}

	public Peer(String id, String host) {
		this.id = id;
		this.tracker = host;
	}

	private void init() throws IOException {
		
		//MulticastConnection _multi = new MulticastConnection(this);
		//new Thread(_multi).start();
		
		javaspaceConn = new JavaspaceConnection(tracker, this);
		JoinProtocol.monitor(javaspaceConn);
		JobProtocol.monitor(javaspaceConn);
		new Thread(javaspaceConn).start();					
	}
	
	public void becomeLeader() {
		System.out.println("OWNRY I HAF POWA"); System.out.flush();
		this.isLeader = true;
	}

	@Override
	public void run() {
		try {
			init();
			while(true) {
				JobEnvelope je = jobQueue.take();
				new Thread(je.job).run();
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {			
			e.printStackTrace();
		}
	}
	
	public void addJob(JobEnvelope je) {
		jobQueue.add(je);
	}
	
	public JobEnvelope getJob() {
		try {
			return jobQueue.take();
		} catch (InterruptedException e) {
			return getJob();
		}
	}
	
	public void addPeer(String id) {
		System.out.println("Adding peer: " + id);
	}
	
	public void createJob() {
		
	}
	
	public void test() {
		JobEnvelope je = new JobEnvelope();
		Job j = new Job();
		je.job = j;
		j.addClass(Main.class);
		j.addClass(Foo.class);
		j.addClass(No.class);
		j.setEntryPoint(Main.class);
		System.out.println("\tpackaged classes: " ); System.out.flush();
		for (String c : je.job.classMap.keySet()) {
			System.out.println("\t\t" + c);System.out.flush();
		}
		Message<JobEnvelope> m = new Message<JobEnvelope>();
		m.id = "0";
		m.protocol = JobProtocol.NAME;
		m.type = JobProtocol.MessageTypes.request.toString();
		m.data = je;
		javaspaceConn.write(m);		
	}
}
